package se.perp.c4.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import se.perp.c4.control.Main;

public class StartClientDialog extends JDialog implements ActionListener, CaretListener {

    private JButton okButton,  cancelButton;
    private JTextField ipField;
    private JTextField portField;
    private JTextField nameField;

    public enum Choice {

        OK, CANCEL
    };
    private Choice choice = Choice.CANCEL;
    private final Color defaultBg;
    private final MainMenu mainMenu;
    private boolean ipOK = false,  portOK = true, nameOK = true;

    public StartClientDialog(Window owner,MainMenu mainMenu, String defaultName, String defaultHost, String defaultPort) {
        super(owner);

        this.mainMenu = mainMenu;

        setModalityType(DEFAULT_MODALITY_TYPE);

        setDefaultCloseOperation(HIDE_ON_CLOSE);

        setTitle("Start client");
        setLayout(new BorderLayout());

        JLabel nameLabel = new JLabel("Your name:");
        nameField = new JTextField(12);
        nameField.setText(defaultName);
        nameField.addCaretListener(this);

        JLabel ipLabel = new JLabel("IP address:");
        ipField = new JTextField(12);
        ipField.setText(defaultHost);
        ipOK = isValidIP(ipField.getText());
        if (!ipOK) {
            ipField.setBackground(Color.PINK);
        }
        ipField.addCaretListener(this);
        ipField.requestFocus();

        JLabel portLabel = new JLabel("Port number:");
        portField = new JTextField(defaultPort);
        defaultBg = portField.getBackground();
        portOK = isValidPort(portField.getText());
        if (!portOK) {
            portField.setBackground(Color.PINK);
        }
        portField.setSelectionStart(0);
        portField.setSelectionEnd(portField.getText().length());
        portField.addCaretListener(this);

        okButton = new JButton("OK");
        okButton.addActionListener(this);
        okButton.setMnemonic('O');
        okButton.setEnabled(ipOK && portOK);
        getRootPane().setDefaultButton(okButton);

        cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(this);
        cancelButton.setMnemonic('C');

        JPanel p = new JPanel(new GridLayout(4, 2, 5, 5));
        p.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        p.add(nameLabel);
        p.add(nameField);

        p.add(ipLabel);
        p.add(ipField);

        p.add(portLabel);
        p.add(portField);

        p.add(okButton);
        p.add(cancelButton);

        add(p, BorderLayout.CENTER);
        pack();

        // TODO: Make ipField gain focus first.

        Dimension osz = owner.getSize();

        setLocation(owner.getX() + (osz.width - getWidth()) / 2,
                owner.getY() + (osz.height - getHeight()) / 2);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
        if (source == okButton) {
            choice = Choice.OK;
            setVisible(false);
        } else if (source == cancelButton) {
            choice = Choice.CANCEL;
            mainMenu.setGameAsClientEnabled(true);
            mainMenu.setGameAsServerEnabled(true);
            setVisible(false);
        }
    }

    public void caretUpdate(CaretEvent e) {
        if (e.getSource() == portField) {
            if (isValidPort(portField.getText())) {
                portField.setBackground(defaultBg);
                portOK = true;
            } else {
                portField.setBackground(Color.PINK);
                portOK = false;
            }
        } else if (e.getSource() == ipField) {
            if (isValidIP(ipField.getText())) {
                ipField.setBackground(defaultBg);
                ipOK = true;
            } else {
                ipField.setBackground(Color.PINK);
                ipOK = false;
            }
        } else if (e.getSource() == nameField) {
            if (nameField.getText().length() > Main.MAX_NAME_LENGTH) {
                nameField.setBackground(Color.PINK);
                nameOK = false;
            } else {
                nameField.setBackground(defaultBg);
                nameOK = true;
            }
        }
        okButton.setEnabled(ipOK && portOK && nameOK);
    }

    public Choice getChoice() {
        return choice;
    }

    public int getPortNumber() {
        try {
            return Integer.parseInt(portField.getText());
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    public String getIP() {
        return ipField.getText();
    }

    public String getPlayerName() {
        return nameField.getText();
    }

    private boolean isValidPort(String text) {
        try {
            int i = Integer.parseInt(text);
            return 1023 < i && i < 65536;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private boolean isValidIP(String text) {

        if (text == null || text.length() < 7) {
            return false;
        }
        text = text.trim();

        if (text.equals("localhost")) {
            return true;
        }

        boolean startsAndEndsWithDigit = Character.isDigit(text.charAt(0)) &&
                Character.isDigit(text.charAt(text.length() - 1));
        if (!startsAndEndsWithDigit) {
            return false;
        }

        String[] parts = text.split("\\.");

        if (parts.length != 4) {
            return false;
        }

        for (String s : parts) {
            try {
                int i = Integer.parseInt(s);
                if (i < 0 || i > 255) {
                    return false;
                }
            } catch (NumberFormatException e) {
                return false;
            }
        }
        return true;
    }
}
